package process;

import data.Document;
import data.DocumentCollection;
import data.Term;
import data.TermCollection;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import transform.Parser;
import transform.Stopper;

/**
 * Pembaca statistik dari dokumen, dijalankan dalam sebuah thread Sebuah
 * DocumentStatisticReader berasosiasi dengan sebuah DocumentCollection yang
 * akan diproses. Proses statistic reading akan selesai jikan crawling telah
 * selesai dilakukan dan dokumen telah habis diproses.
 *
 * @author Muqtafi Akhmad
 */
public abstract class DocumentStatisticsReader implements Runnable {

    /**
     * array dari subfolders bagi index files
     */
    public static String subfolders[] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
        "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "etc"};

    /**
     * mengisikan ID dari worker
     *
     * @param ID ID dari worker
     */
    public void setID(String ID) {
        this.ID = ID;
    }

    /**
     * mendapatkan ID dari worker
     *
     * @return ID dari worker
     */
    public String getID() {
        return ID;
    }

    /**
     * mengisikan term collection
     *
     * @param termCollection term collection
     */
    public void setTermCollection(TermCollection termCollection) {
        this.termCollection = termCollection;
    }

    /**
     * mendapatkan referensi ke term collection
     *
     * @return term collection
     */
    public TermCollection getTermCollection() {
        return termCollection;
    }

    /**
     * mengisikan document collection
     *
     * @param documentCollection document collection
     */
    public void setDocumentCollection(DocumentCollection documentCollection) {
        this.documentCollection = documentCollection;
    }

    /**
     * mengisikan parser dokumen
     *
     * @param parser parser
     */
    public void setParser(Parser parser) {
        this.parser = parser;
    }

    /**
     * mengisikan stopper
     *
     * @param stopper stopper
     */
    public void setStopper(Stopper stopper) {
        this.stopper = stopper;
    }

    /**
     * mengembalikan referensi ke document collection
     *
     * @return document collection
     */
    public DocumentCollection getDocumentCollection() {
        return documentCollection;
    }

    /**
     * mengembalikan parser
     *
     * @return parser
     */
    public Parser getParser() {
        return parser;
    }

    /**
     * mengembalikan stopper
     *
     * @return stopper
     */
    public Stopper getStopper() {
        return stopper;
    }
    /**
     * jumlah term maksimal yang ditampung dalam term collection
     */
    public static final Integer MAX_TERMS_IN_MEMORY = 20000;
    /**
     * jumlah runs file maksimal dalam memory ketika proses merge runs file ke
     * dalam index files
     */
    public static final Integer MAX_RUNS_IN_MEMORY = 5;
    /**
     * ID dari worker
     */
    private String ID;
    /**
     * reference document collection
     */
    private DocumentCollection documentCollection;
    /**
     * reference ke term collection
     */
    private TermCollection termCollection;
    /**
     * reference ke parser
     */
    private Parser parser;
    /**
     * reference ke stopper
     */
    private Stopper stopper;

    /**
     * menciptakan folder untuk woker dan subfolders di bawahnya
     *
     * @param rootFolder folder dari index directory
     */
    private void createFolders(File rootFolder) {
        int i;
        // menciptakan folder
        File termDir = new File(rootFolder.getAbsolutePath() + File.separator + IndexGenerator._result_dir + File.separator + ID);
        if (!termDir.exists()) {
            termDir.mkdir();
        }
        // menciptakan sub folder berdasarkan huruf pertama kata
        for (i = 0; i < subfolders.length; i++) {
            File subfolder = new File(termDir.getAbsolutePath() + File.separator + subfolders[i]);
            subfolder.mkdir();
        }
    }

    @Override
    public final void run() {
        File rootFolder = new File(".");
        createFolders(rootFolder);
        this.termCollection.setTermDirectory(rootFolder.getAbsolutePath() + File.separator + IndexGenerator._result_dir + File.separator + ID);
        System.out.println("## Start " + ID);
        // ulangi hingga dokumen habis
        while ((!documentCollection.isFinishedCollecting()) || (documentCollection.getDocumentCount() > 0)) {
            try {
                // mendapatkan dokumen dari collection
                Document processedDocument = documentCollection.getDocument();
                if (processedDocument != null) {
                    if (documentCollection.getDocumentCount() % 1000 == 0) {
                        System.out.println("## " + ID + ", remaining : " + documentCollection.getDocumentCount() + " docs");
                    }
                    // parse dokumen
                    HashMap<String, Term> documentTerms = parser.doParse(processedDocument);
                    documentTerms = stopper.doStop(documentTerms);
                    Iterator it = documentTerms.entrySet().iterator();
                    // simpan term ke dalam term collection
                    while (it.hasNext()) {
                        Map.Entry pairs = (Map.Entry) it.next();
                        Term term = (Term) pairs.getValue();
                        if (!termCollection.isExists(term)) {
                            // cek pertama, jika tidak ada perintahkan untuk membaca dari file index
                            termCollection.readFromFile(term);
                        }
                        if (termCollection.isExists(term)) {
                            termCollection.merge(term);
                        } else {
                            termCollection.addTerm(term);
                        }
                    }
                }
                if (termCollection.getAllTerms().size() > MAX_TERMS_IN_MEMORY) {
                    termCollection.writeToRuns();
                    termCollection.purgeMemory();
                }
            } catch (Exception ex) {
            }
        }
        // paksa semua term sisa dalam memory term collection untuk dituliskan ke file
        termCollection.writeToRuns();
        termCollection.purgeMemory();
        // merge semua runs file
        termCollection.mergeAllRuns();
        System.out.println("## Stop " + ID);
    }
}